import 'package:dio/dio.dart';
import 'package:flutter_app/net_data/base/security_util.dart';

class MyLogsInterceptor extends Interceptor {
  static const int maxLen=800;
  MyLogsInterceptor({
    this.request = true,
    this.requestHeader = true,
    this.requestBody = true,
    this.responseHeader = true,
    this.responseBody = true,
    this.error = true,
    this.logPrint = print,
    this.encrypt
  });

  bool ?encrypt=false;
  /// Print request [Options]
  bool request;

  /// Print request header [Options.headers]
  bool requestHeader;

  /// Print request data [Options.data]
  bool requestBody;

  /// Print [Response.data]
  bool responseBody;

  /// Print [Response.headers]
  bool responseHeader;

  /// Print error message
  bool error;

  /// Log printer; defaults print log to console.
  /// In flutter, you'd better use debugPrint.
  /// you can also write log in a file, for example:
  ///```dart
  ///  var file=File("./log.txt");
  ///  var sink=file.openWrite();
  ///  dio.interceptors.add(LogInterceptor(logPrint: sink.writeln));
  ///  ...
  ///  await sink.close();
  ///```
  void Function(Object object) logPrint;

  // @override
  // void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
  //   super.onRequest(options, handler);
  // }
  @override
  Future onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    logPrint('*** Request ***');

    printKV('uri', Uri.decodeFull(options.uri.toString()));

    if (request) {
      printKV('method', options.method);
      printKV('responseType', options.responseType?.toString() as Object);
      printKV('followRedirects', options.followRedirects);
      printKV('connectTimeout', options.connectTimeout);
      printKV('receiveTimeout', options.receiveTimeout);
      printKV('extra', options.extra);
    }
    if (requestHeader) {
      logPrint('headers:');
      options.headers.forEach((key, v) => printKV(' $key', v));
    }
    if (requestBody) {
      if(options.data is FormData){
        FormData formData= options.data;
        for(MapEntry mapEntry in  formData.fields){
          if(!encrypt!){
            // logPrint('request params: ${(mapEntry??{}).toString()}');
            printLongLog('request params: ${(mapEntry??{}).toString()}');
          }else{
            String  responseData = await SecurityUtil.decrypt((mapEntry.value??"").toString());
            // logPrint('request params: $responseData');
            printLongLog('request params: $responseData');
          }

        }
      }else{
        if(!encrypt!){
          // logPrint('request params: ${((options.data)??{}).toString()}');
          printLongLog('request params: ${((options.data)??{}).toString()}');
        }else{
          String  responseData = await SecurityUtil.decrypt(((options.data)??"").toString());
          // logPrint('request params: $responseData');
          printLongLog('request params: $responseData');
        }

      }
    }
    logPrint('');
  }

  @override
  Future onError(DioError err, ErrorInterceptorHandler handler) async {
    if (error) {
      logPrint('*** DioError ***:');
      logPrint('uri: ${err.response?.realUri}');
      logPrint('$err');
      if (err.response != null) {
        _printResponse(err.response!);
      }
      logPrint('');
    }
  }

  // @override
  // Future onResponse(Response response) async {
  //   logPrint('*** Response ***');
  //   _printResponse(response);
  // }

  Future<void> _printResponse(Response response) async {
    printKV('uri', response.requestOptions!.uri);
    if (responseHeader) {
      printKV('statusCode', response.statusCode as Object);
      if (response.isRedirect == true) {
        printKV('redirect', response.realUri);
      }
      if (response.headers != null) {
        logPrint('headers:');
        response.headers.forEach((key, v) => printKV(' $key', v.join(',')));
      }
    }
    if (responseBody) {
      logPrint('Response Text:');
      String log=response.toString();
      if(log.length>maxLen){
        if(!encrypt!){
          printLongLog(log);
        }else{
          String  responseData = await SecurityUtil.decrypt(((log)??"").toString());
          printLongLog(responseData);
        }
      }else{
        if(!encrypt!){
          printAll(log);
        }else{
          String  responseData = await SecurityUtil.decrypt(((log)??"").toString());
          printAll(responseData);
        }
      }






    }
    logPrint('');
  }

  void printKV(String key, Object v) {
    logPrint('$key: $v');
  }

  void printAll(msg) {
    msg.toString().split('\n').forEach(logPrint);
  }

  void printLongLog(String log){
    if(log==null){
      return;
    }
    int num=(log.length/maxLen).ceil();
    for(int i=0;i<num;i++){
      int s=i*maxLen;
      if(s>log.length){
        break;
      }
      int e=i*maxLen+maxLen;
      if(e>log.length){
        e=log.length;
      }
      log.substring(s,e).toString().split('\n').forEach(logPrint);
    }

  }
}
